/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/** ************************************************************************************************
 * @file     Xspi_Ip.c                                                                           *
 * @brief    LLD XSPI IP Driver                                                                       *
 * @author   Department/Semidrive                                                                     *
 * @date     2025/02/25                                                             *
 *                                                                                                 *
 **************************************************************************************************/

#include "Xspi_Ip.h"
#include "Xspi_IpAsm.h"
#include "Semag.h"

/* PRQA S 0306,0310,0314,0316,0326,0488,0750,0759,1881,3673,4404 EOF */

/***************************************************************************************************
 *                                 Private Macro definition                                        *
 **************************************************************************************************/

#define XSPI_DLL_BYPASS_MIN_REFCLK          (50000000u)
#define XSPI_IP_XFER_POLLING_TIMEOUT        (100000u)     /* Timeout for read and write transfers */
#define XSPI_MAX_RBUF_ENTRY_NUM             (64u)
#define XSPI_MAX_RBUF_BLOCK_SIZE            (1024u)

/* default use override mode to training  */
#ifndef XSPI_IP_DLL_USE_LOCK_MODE
#define XSPI_IP_DLL_USE_LOCK_MODE (0)
#endif /* #ifndef XSPI_IP_DLL_USE_LOCK_MODE */

#define XSPI_IP_DLL_LOCK_MODE_REFCLK_MIN (65000000u)
#define XSPI_IP_DUMMY_DQS_MODE_REFCLK_MAX (200000000u)
#define XSPI_IP_DLL_OVERRIDE_MODE_STEP   (0x7Fu)
#define XSPI_IP_DLL_LOCKE_MODE_STEP      (0x1Fu)

#define XSPI_IP_IDLE_TIMEOUT_CYCLES (10000u)
#define XSPI_IP_DLL_ENABLE_TIMEOUT_CYCLES (100000u)
#define XSPI_IP_READ_DONE_TIMEOUT_CYCLES (10000u)
#define XSPI_IP_WRITE_DONE_TIMEOUT_CYCLES (100u)
#define XSPI_IP_KEY_READY_TIMEOUT_CYCLES (10000u)
#define XSPI_IP_WAIT_TRIGGER_COMPLETE_TIMEOUT (100u)

#define XSPI_IP_MODE_CTRL (0x0u)
#define XSPI_IP_MODE_CTRL_SW_RST_LSB (31U)
#define XSPI_IP_MODE_CTRL_RBUF_MODE_SEL_LSB (18u)
#define XSPI_IP_MODE_CTRL_BYTE_SWAP_LSB (12U)
#define XSPI_IP_MODE_CTRL_DEV_LS_LSB (4U)
#define XSPI_IP_MODE_CTRL_SW_RST XSPI_BIT(31)
#define XSPI_IP_MODE_CTRL_IDLE XSPI_BIT(30)
#define XSPI_IP_MODE_CTRL_XIP XSPI_BIT(9)
#define XSPI_IP_MODE_CTRL_RX_MODE XSPI_BIT(8)


#define XSPI_IP_DEV_SIZE (0x4u)
#define XSPI_IP_DEV_SIZE_DEV1_HYPER_RAM_EN_LSB (16U)
#define XSPI_IP_DEV_SIZE_SIZE_LSB (8u)
#define XSPI_IP_DEV_SIZE_SIZE_MASK (0x1Fu)

#define XSPI_IP_SIP_PKG_PARAL (0x8u)
#define XSPI_IP_QUAD_DUP_MODE XSPI_BIT(2)
#define XSPI_IP_PARAL4_REG_ACCESS_EN XSPI_BIT(1)
#define XSPI_IP_PARAL_CS0_REUSE XSPI_BIT(0)

#define XSPI_IP_INT_ST_FUC (0x10u)
#define XSPI_IP_INT_ST_FUC_INDIRECT_DMA_RD_DONE XSPI_BIT(10u)
#define XSPI_IP_INT_ST_FUC_TX_FRE_EMPTY XSPI_BIT(9u)
#define XSPI_IP_INT_ST_FUC_RX_FRE_FULL XSPI_BIT(8u)
#define XSPI_IP_INT_ST_FUC_POLLING_TIMEOUT BIT(7u)
#define XSPI_IP_INT_ST_FUC_POLLING_MATCH XSPI_BIT(6u)
#define XSPI_IP_INT_ST_FUC_FIFO_LEVEL_TRIG (XSPI_IP_INT_ST_FUC_RX_FRE_FULL | XSPI_IP_INT_ST_FUC_TX_FRE_EMPTY)
#define XSPI_IP_INT_ST_FUC_DIRECT_RD_DONE XSPI_BIT(3u)
#define XSPI_IP_INT_ST_FUC_DIRECT_WR_DONE XSPI_BIT(2u)
#define XSPI_IP_INT_ST_FUC_INDIRECT_RD_DONE XSPI_BIT(1u)
#define XSPI_IP_INT_ST_FUC_INDIRECT_WR_DONE XSPI_BIT(0u)
#define XSPI_IP_INT_ST_FUC_IND_COMP    \
         (XSPI_IP_INT_ST_FUC_INDIRECT_DMA_RD_DONE | XSPI_IP_INT_ST_FUC_INDIRECT_WR_DONE)


#define XSPI_IP_INT_EN_FUC (0x14u)

#define XSPI_IP_INT_ST_ERR (0x18u)
#define XSPI_IP_INT_ST_ERR_INDIRECT_WR_FIREWALL XSPI_BIT(22)
#define XSPI_IP_INT_ST_ERR_INDIRECT_RD_FIREWALL XSPI_BIT(21)

#define XSPI_IP_INT_EN_ERR (0x1Cu)

#define XSPI_IP_INT_EN_ERR_FUC (0x20u)

#define XSPI_IP_DATA_INIEGRITY (0x30u)

#define XSPI_IP_IO_FMUX1 (0x40u)
#define XSPI_IP_IO_FMUX1_DEFAULT (0x76543210u)

#define XSPI_IP_IO_FMUX2 (0x44u)
#define XSPI_IP_IO_FMUX2_DEFAULT (0xFEDCBA98u)

#define XSPI_IP_IO1_FMUX1 (0x48u)

#define XSPI_IP_IO1_FMUX2 (0x4Cu)

#define XSPI_IP_IO_CTRL (0x60u)
#define XSPI_IP_IO_CTRL_SW_PAD_RSTN_LSB (1U)
#define XSPI_IP_IO_CTRL_SW_PAD_RST_EN_LSB (0U)

#define XSPI_IP_ADDR_OFFSET (0x70u)

#define XSPI_IP_MISC (0x80u)
#define XSPI_IP_MISC_CAPTURE_SEL_LSB (12U)
#define XSPI_IP_MISC_INDIRECT_AXI_RD_EN XSPI_BIT(11u)
#define XSPI_IP_MISC_INDIRECT_AXI_WR_EN XSPI_BIT(10u)
#define XSPI_IP_MISC_INDIRECT_AXI_WR_EN_LSB (10U)
#define XSPI_IP_MISC_RX_ENABLE_MODE_LSB (9U)
#define XSPI_IP_MISC_IMMEDIATE_LSB (8U)

#define XSPI_IP_AXI_CTRL (0x84u)
#define XSPI_IP_TIMEOUT_THRE_LSB (0u)
#define XSPI_IP_TIMEOUT_BRESP_MODE_LSB (25u)

#define XSPI_IP_SCLK_CTRL (0xC0u)
#define XSPI_IP_SCLK_CTRL_RX_SEL_MASK (3u)
#define XSPI_IP_SCLK_CTRL_RX_SEL_LSB (2u)
#define XSPI_IP_SCLK_CTRL_DLL_EN_LSB (1u)

#define XSPI_IP_CS_CTRL (0xC4u)
#define XSPI_IP_CS_CTRL_SEL_MASK (0xFu)
#define XSPI_IP_CS_CTRL_HW_SEL_MASK (0x3u)
#define XSPI_IP_CS_CTRL_HW_SEL_DEV1 (0x2u)
#define XSPI_IP_CS_CTRL_HW_SEL_DEV2 (0x1u)
#define XSPI_IP_CS_CTRL_HW_SEL_AUTO (0x3u)
#define XSPI_IP_CS_CTRL_HW_SEL_LSB (27u)
#define XSPI_IP_CS_CTRL_SW_SEL_MASK (0x3u)
#define XSPI_IP_CS_CTRL_SW_SEL_DEV1 (0x2u)
#define XSPI_IP_CS_CTRL_SW_SEL_DEV2 (0x1u)
#define XSPI_IP_CS_CTRL_SW_SEL_LSB (25u)
#define XSPI_IP_CS_CTRL_SW XSPI_BIT(24)
#define XSPI_IP_CS_CTRL_TIME_DELAY_MASK ((uint32_t)0xFu)
#define XSPI_IP_CS_CTRL_TIME_SHSL_DELAY_MASK ((uint32_t)0x1Fu)
#define XSPI_IP_CS_CTRL_TSLCH_LSB (16u)
#define XSPI_IP_CS_CTRL_TSHSL_LSB (8u)
#define XSPI_IP_CS_CTRL_TCHSH_LSB (0u)

#define XSPI_IP_HYPERBUS_CTRL (0xD0u)
#define XSPI_IP_HYPERBUS_CTRL_PROFILE20_EN_LSB (3U)
#define XSPI_IP_HYPERBUS_CTRL_AM_LSB (2U)
#define XSPI_IP_HYPERBUS_CTRL_AS_LSB (1U)
#define XSPI_IP_HYPERBUS_CTRL_EN_LSB (0U)


#define XSPI_IP_DLL_CTRL (0xE0u)
#define XSPI_IP_DLL_CTRL_SLV_UPD_GATE_LSB (31U)
#define XSPI_IP_DLL_CTRL_OVERRIDE_VAL_LSB (9U)
#define LS_IP_DLL_CTRL_OVERRIDE_ENABLE XSPI_BIT(8U)
#define XSPI_IP_DLL_CTRL_SLV_TARGET_LSB (1U)
#define XSPI_IP_DLL_CTRL_LOCK_ENABLE XSPI_BIT(0U)

#define XSPI_IP_STATUS (0xE4u)
#define XSPI_IP_STATUS_SLV_LOCK XSPI_BIT(16U)

#define XSPI_IP_DLL1_CTRL (0xE8u)

#define XSPI_IP_DLL1_STATUS (0xECu)

#define XSPI_IP_DIRECT_RD_PH_CTRL (0x100u)
#define XSPI_IP_DIRECT_WR_PH_CTRL (0x104u)
#define XSPI_IP_DIRECT_DATA_DDR_RATE XSPI_BIT(26)
#define XSPI_IP_DIRECT_DATA_LINE_MASK (0x3u)
#define XSPI_IP_DIRECT_DATA_LINE_LSB (24u)
#define XSPI_IP_DIRECT_MODE_EN XSPI_BIT(21)
#define XSPI_IP_DIRECT_MODE_SIZE_MASK ((uint32_t)0x3u)
#define XSPI_IP_DIRECT_MODE_SIZE_LSB (19u)
#define XSPI_IP_DIRECT_MODE_DDR_RATE XSPI_BIT(18)
#define XSPI_IP_DIRECT_MODE_LINE_MASK (0x3u)
#define XSPI_IP_DIRECT_MODE_LINE_LSB (16u)
#define XSPI_IP_DIRECT_ADDR_SIZE_MASK (0x3u)
#define XSPI_IP_DIRECT_ADDR_SIZE_LSB (11u)
#define XSPI_IP_DIRECT_ADDR_DDR_RATE XSPI_BIT(10)
#define XSPI_IP_DIRECT_ADDR_LINE_MASK (0x3u)
#define XSPI_IP_DIRECT_ADDR_LINE_LSB (8u)
#define XSPI_IP_DIRECT_CMD_EN XSPI_BIT(5)
#define XSPI_IP_DIRECT_CMD_SIZE_MASK (0x3u)
#define XSPI_IP_DIRECT_CMD_SIZE_LSB (3u)
#define XSPI_IP_DIRECT_CMD_DDR_RATE XSPI_BIT(2)
#define XSPI_IP_DIRECT_CMD_LINE_MASK (0x3u)
#define XSPI_IP_DIRECT_CMD_LINE_LSB (0u)

#define XSPI_IP_DIRECT_C_CODE (0x114u)
#define XSPI_IP_DIRECT_C_CODE_WCODE_LSB (16U)
#define XSPI_IP_DIRECT_C_CODE_RCODE_LSB (0U)
#define XSPI_IP_DIRECT_C_CODE_MASK (0xFFFFu)

#define XSPI_IP_DIRECT_WREN (0x118u)
#define XSPI_IP_DIRECT_WREN_CODE_LSB (16U)
#define XSPI_IP_DIRECT_WREN_LSB (0u)
#define XSPI_IP_DIRECT_WREN_INVERT_CODE (0xF906UL)
#define XSPI_IP_DIRECT_WREN_CODE (0x06UL)

#define XSPI_IP_DIRECT_M_CODE (0x11Cu)

#define XSPI_IP_DIRECT_D_CYC (0x120u)
#define XSPI_IP_DIRECT_D_CYC_RD_LSB (0u)
#define XSPI_IP_DIRECT_D_CYC_RD_MASK (0x1Fu)
#define XSPI_IP_DIRECT_D_CYC_WR_LSB (8u)
#define XSPI_IP_DIRECT_D_CYC_WR_MASK (0x1Fu)

#define XSPI_IP_INDIRECT_WR_CTRL (0x200u)
#define XSPI_IP_INDIRECT_WR_CTRL_W_TRIGGER XSPI_BIT(0)

#define XSPI_IP_INDIRECT_WR_PH_CTRL (0x204u)
#define XSPI_IP_INDIRECT_RD_PH_CTRL (0x304u)
#define XSPI_IP_INDIRECT_DATA_EN XSPI_BIT(27)
#define XSPI_IP_INDIRECT_DATA_DDR_RATE XSPI_BIT(26)
#define XSPI_IP_INDIRECT_DATA_LINE_MASK (0x3u)
#define XSPI_IP_INDIRECT_DATA_LINE_LSB (24u)
#define XSPI_IP_INDIRECT_ADDR_EN XSPI_BIT(13)
#define XSPI_IP_INDIRECT_ADDR_SIZE_MASK (0x3u)
#define XSPI_IP_INDIRECT_ADDR_SIZE_LSB (11u)
#define XSPI_IP_INDIRECT_ADDR_DDR_RATE XSPI_BIT(10)
#define XSPI_IP_INDIRECT_ADDR_LINE_MASK (0x3u)
#define XSPI_IP_INDIRECT_ADDR_LINE_LSB (8u)
#define XSPI_IP_INDIRECT_CMD_EN XSPI_BIT(5)
#define XSPI_IP_INDIRECT_CMD_SIZE_2_BYTES XSPI_BIT(3u)
#define XSPI_IP_INDIRECT_CMD_DDR_RATE XSPI_BIT(2)
#define XSPI_IP_INDIRECT_CMD_LINE_MASK (0x3u)
#define XSPI_IP_INDIRECT_CMD_LINE_LSB (0u)

#define XSPI_IP_INDIRECT_WR_CMD_CODE (0x208u)
#define XSPI_IP_INDIRECT_WR_CMD_CODE_MASK (0xFFFFu)

#define XSPI_IP_INDIRECT_WR_ADDR (0x20Cu)

#define XSPI_IP_INDIRECT_WR_SIZE (0x210u)

#define XSPI_IP_INDIRECT_WR_CYC (0x214u)
#define XSPI_IP_INDIRECT_WR_CYC_MASK (0x1Fu)

#define XSPI_IP_INDIRECT_WR_DMA (0x220u)
#define XSPI_IP_INDIRECT_RD_DMA (0x320u)
#define XSPI_IP_INDIRECT_DMA_TRIG_WML_MASK (0x1Fu)
#define XSPI_IP_INDIRECT_DMA_TRIG_WML_LSB (8u)
#define XSPI_IP_INDIRECT_DMA_SW_ACK XSPI_BIT(2)
#define XSPI_IP_INDIRECT_DMA_SINGLE_EN XSPI_BIT(1)
#define XSPI_IP_INDIRECT_DMA_REQ_EN XSPI_BIT(0)

#define XSPI_IP_INDIRECT_TX_BUF (0x240u)
#define XSPI_IP_INDIRECT_TX_BUF_ENTRY_MASK (0xFFu)
#define XSPI_IP_INDIRECT_TX_BUF_ENTRY_LSB (16)
#define XSPI_IP_INDIRECT_TX_BUF_LEVEL_MASK (0xFFu)
#define XSPI_IP_INDIRECT_TX_BUF_LEVEL_LSB (8)
#define XSPI_IP_INDIRECT_TX_BUF_FLUSH_LSB (0)


#define XSPI_IP_INDIRECT_WDATA (0x280u)

#define XSPI_IP_INDIRECT_RD_CTRL (0x300u)
#define XSPI_IP_INDIRECT_RD_CTRL_P_SIZE_LSB (3)
#define XSPI_IP_INDIRECT_RD_CTRL_P_TRIGGER_LSB (1)
#define XSPI_IP_INDIRECT_RD_CTRL_R_TRIGGER XSPI_BIT(0)

#define XSPI_IP_INDIRECT_RD_CMD_CODE (0x308u)
#define XSPI_IP_INDIRECT_RD_CMD_CODE_MASK (0xFFu)

#define XSPI_IP_INDIRECT_RD_ADDR (0x30Cu)

#define XSPI_IP_INDIRECT_RD_SIZE (0x310u)

#define XSPI_IP_INDIRECT_RD_CYC (0x314u)
#define XSPI_IP_INDIRECT_RD_CYC_MASK (0x1Fu)

#define XSPI_IP_INDIRECT_RD_M_CODE (0x318u)

#define XSPI_IP_INDIRECT_P_VALUE (0x330u)

#define XSPI_IP_INDIRECT_P_MASK (0x334u)

#define XSPI_IP_INDIRECT_P_TIME (0x338u)
#define XSPI_IP_INDIRECT_P_TIME_MAX_OP_LSB (16)

#define XSPI_IP_INDIRECT_RX_BUF (0x340u)
#define XSPI_IP_INDIRECT_RX_BUF_ENTRY_MASK (0xFFu)
#define XSPI_IP_INDIRECT_RX_BUF_ENTRY_LSB (16)
#define XSPI_IP_INDIRECT_RX_BUF_LEVEL_MASK (0xFFu)
#define XSPI_IP_INDIRECT_RX_BUF_LEVEL_LSB (8)
#define XSPI_IP_INDIRECT_RX_BUF_FLUSH_LSB (0)

#define XSPI_IP_INDIRECT_RDATA (0x380u)

#define XSPI_IP_RBUF_HIT_CNTR (0x390u)

#define XSPI_IP_RBUF_MISS_CNTR (0x394u)

#define XSPI_IP_GROUP_MERGE (0x3A0u)

#define XSPI_IP_RBUF_CTRL (0x400u)
#define XSPI_IP_RBUF_CTRL_ENTRY_NUM_LSB (8U)
#define XSPI_IP_RBUF_CTRL_PREFETCH_EN_LSB (16U)
#define XSPI_IP_RBUF_CTRL_FLUSH_LSB (17U)

#define XSPI_IP_GID_MASK (0x404u)

#define XSPI_IP_GID_MATCH (0x408u)

#define XSPI_IP_IMG_REGION_START (0x500u)

#define XSPI_IP_IMG_REGION_END_ADDR (0x504u)

#define XSPI_IP_IMG_REGION_CTRL (0x508u)

#define XSPI_IP_IMG_REGION_NONCE0 (0x510u)

#define XSPI_IP_IMG_REGION_NONCE1 (0x514u)

#define XSPI_IP_IMG_REGION_NONCE2 (0x518u)

#define XSPI_IP_IMG_REGION_NONCE3 (0x51Cu)

#define XSPI_IP_IMG_RFD (0x590u)

#define XSPI_IP_MON_OP_TIME (0x600u)

#define XSPI_IP_CMD_MON_CTRL (0x610u)

#define XSPI_IP_MON_REGION_START_ADDR (0x614u)

#define XSPI_IP_MON_REGION_END_ADDR (0x618u)

#define XSPI_IP_MON_CMD_VALUE (0x654u)

#define XSPI_IP_MS_CTRL (0x800u)

#define XSPI_IP_MS_WAIT_TIME (0x810u)

#define XSPI_IP_MS_TIMEOUT (0x81Cu)

#define XSPI_IP_MS_INT_ST (0x820u)

#define XSPI_IP_MS_INT_EN (0x828u)

#define XSPI_IP_INDR_WR_PTC (0x900u)

#define XSPI_IP_INDR_RD_PTC (0x904u)

#define XSPI_IP_DIRECT_WR_PTC (0x908u)

#define XSPI_IP_DIRECT_RD_PTC (0x90Cu)

#define XSPI_IP_INDR_WR_PTA (0x920u)

#define XSPI_IP_INDR_WR_PTD (0x924u)

#define XSPI_IP_INDR_RD_PTA (0x928u)

#define XSPI_IP_INDR_RD_PTD (0x92Cu)

#define XSPI_IP_DIRECT_WR_PTA (0x930u)

#define XSPI_IP_DIRECT_WR_PTD (0x934u)

#define XSPI_IP_DIRECT_RD_PTA (0x938u)

#define XSPI_IP_DIRECT_RD_PTD (0x93Cu)

#define XSPI_IP_ERR_INJ_EN (0xC00u)

#define XSPI_IP_INJ_DATA (0xC04u)

#define XSPI_IP_INJ_CODE (0xC08u)

#define XSPI_IP_FATAL_ERR_ST (0xC20u)

#define XSPI_IP_FATAL_ERR_EN (0xC28u)

#define XSPI_IP_CORE_ERR_ST (0xC30u)

#define XSPI_IP_AXI_UNC_ERR_ST (0xC34u)

#define XSPI_IP_APB_UNC_ERR_ST (0xC38u)

#define XSPI_IP_DMA_ERR_ST (0xC3Cu)

#define XSPI_IP_COR_ERR_EN (0xC50u)

#define XSPI_IP_AXI_UNC_ERR_EN (0xC54u)

#define XSPI_IP_APB_UNC_ERR_EN (0xC58u)

#define XSPI_IP_DMA_ERR_EN (0xC5Cu)

#define XSPI_IP_CTRL_ERR_ST (0xC60u)

#define XSPI_IP_CTRL_ERR_EN (0xC68u)

#define XSPI_IP_PROT_REGION_MAX_NUM (4u)
#define XSPI_IP_PROT_ADDR_REG (0xD00u)
#define XSPI_IP_PROT_CS_LSB (24)
#define XSPI_IP_PROT_ADDR_MASK (0xFFFFFu)
#define XSPI_IP_PROT_ADDR_CS_MASK (XSPI_IP_PROT_ADDR_MASK | XSPI_BIT(XSPI_IP_PROT_CS_LSB))

#define XSPI_IP_PROT_RANGE_REG (0xD10u)
#define XSPI_IP_PROT_RANGE_MASK (0xFFFFFu)

#define XSPI_IP_WR_PROT_PER_EN_REG (0xD20u)
#define XSPI_IP_WR_RD_PROT_MASK    (0x3u)
#define XSPI_IP_WR_RD_PROT_PER_MID_MASK (0xFu)
#define XSPI_IP_WR_RD_PROT_PER_MID_LSB (2)

#define XSPI_IP_RD_PROT_PER_EN_REG (0xD40u)

#define XSPI_IP_DEV_SIZE_FW (0xD70u)
#define XSPI_IP_DEV_CFG_SEL_MASK XSPI_BIT(16)
#define XSPI_IP_DEV2_SIZE_LSB (8)

#define XSPI_IP_AXI_ACESS_PR_INFO (0xD74u)

#define XSPI_IP_AXI_WR_PR_ADDR (0xD78u)

#define XSPI_IP_AXI_RD_PR_ADDR (0xD7Cu)

#define XSPI_IP_APB_PROT_ERR_INFO (0xD80u)

#define XSPI_IP_LSP_ERR_INJ_EN (0x1000u)

#define XSPI_IP_LSP_CMP_ERR_INJ (0x1004u)

#define XSPI_IP_LSP_ERR_ST (0x1010u)

#define XSPI_IP_LSP_ERR_EN (0x1014u)


#define XSPI_IP_RBUF_8BUFFER_MODE (0u)
#define XSPI_IP_RBUF_4BUFFER_MODE (1u)
#define XSPI_IP_RBUF_BUFFER_MODE (XSPI_IP_RBUF_8BUFFER_MODE)
#define XSPI_IP_RBUF_CHANNEL_NUM (8u >> XSPI_IP_RBUF_BUFFER_MODE)
#define XSPI_IP_RBUF_CHANNEL_TOTAL_SIZE  (512u)

#define XSPI_IP_RFD_START_ADDRESS  (0xF0u)
#define XSPI_IP_MAX_RFD_REGION     (2u)
#define XSPI_IP_RFD_LENGTH         (64u)

/***************************************************************************************************
 *                                    Private Type Declarations                                    *
 **************************************************************************************************/

typedef union {
    uint32_t reg;
    struct {
        Xspi_BitFieldType cLine          : 2;
        Xspi_BitFieldType cRate          : 1;
        Xspi_BitFieldType cSize          : 2;
        Xspi_BitFieldType cEn            : 1;
        Xspi_BitFieldType reserved1      : 2;
        Xspi_BitFieldType aLine          : 2;
        Xspi_BitFieldType aRate          : 1;
        Xspi_BitFieldType aSize          : 2;
        Xspi_BitFieldType aEn            : 1;
        Xspi_BitFieldType reserved2      : 2;
        Xspi_BitFieldType mLine          : 2;  /* valid when reading */
        Xspi_BitFieldType mRate          : 1;  /* valid when reading */
        Xspi_BitFieldType mSize          : 2;  /* valid when reading */
        Xspi_BitFieldType mEn            : 1;  /* valid when reading */
        Xspi_BitFieldType reserved3      : 2;
        Xspi_BitFieldType dLine          : 2;
        Xspi_BitFieldType dRate          : 1;
        Xspi_BitFieldType dEn            : 1;  /* valid for indirect access */
        Xspi_BitFieldType reserved4      : 4;
    } data;
} Xspi_IpRdWrPhaseCtrlType;

typedef struct
{
    uint32_t crc[XSPI_IP_MAX_RFD_REGION];
    uint8_t rfd[XSPI_IP_MAX_RFD_REGION][XSPI_IP_RFD_LENGTH];
} Xspi_IpRfdRegionType;

/***************************************************************************************************
 *                                  Private Variable Definitions                                   *
 **************************************************************************************************/
#ifdef CFG_PLATFORM_MCAL
#define FLS_START_SEC_CONST_UNSPECIFIED
#include "Fls_MemMap.h"
#endif /* #ifdef CFG_PLATFORM_MCAL */

/* PRQA S 3218 1 */
static const uint16 Xspi_IpRbufGidMatch[] =
{
    0x0000u, 0x0000u, 0x0100u, 0x0200u, 0x0300u, 0x0400u, 0x0500u, 0x0600u
};

/* PRQA S 3218 1 */
static const uint16 Xspi_IpRbufGidMask[] =
{
    0x0000u, 0xff00u, 0xff00u, 0xff00u, 0xff00u, 0xff00u, 0xff00u, 0xff00u
};

/* PRQA S 3218 1 */
static const uint32_t Xspi_IpCrc32Table[256] =
{
    0x00000000U, 0x04C11DB7U, 0x09823B6EU, 0x0D4326D9U, 0x130476DCU, 0x17C56B6BU,
    0x1A864DB2U, 0x1E475005U, 0x2608EDB8U, 0x22C9F00FU, 0x2F8AD6D6U, 0x2B4BCB61U,
    0x350C9B64U, 0x31CD86D3U, 0x3C8EA00AU, 0x384FBDBDU, 0x4C11DB70U, 0x48D0C6C7U,
    0x4593E01EU, 0x4152FDA9U, 0x5F15ADACU, 0x5BD4B01BU, 0x569796C2U, 0x52568B75U,
    0x6A1936C8U, 0x6ED82B7FU, 0x639B0DA6U, 0x675A1011U, 0x791D4014U, 0x7DDC5DA3U,
    0x709F7B7AU, 0x745E66CDU, 0x9823B6E0U, 0x9CE2AB57U, 0x91A18D8EU, 0x95609039U,
    0x8B27C03CU, 0x8FE6DD8BU, 0x82A5FB52U, 0x8664E6E5U, 0xBE2B5B58U, 0xBAEA46EFU,
    0xB7A96036U, 0xB3687D81U, 0xAD2F2D84U, 0xA9EE3033U, 0xA4AD16EAU, 0xA06C0B5DU,
    0xD4326D90U, 0xD0F37027U, 0xDDB056FEU, 0xD9714B49U, 0xC7361B4CU, 0xC3F706FBU,
    0xCEB42022U, 0xCA753D95U, 0xF23A8028U, 0xF6FB9D9FU, 0xFBB8BB46U, 0xFF79A6F1U,
    0xE13EF6F4U, 0xE5FFEB43U, 0xE8BCCD9AU, 0xEC7DD02DU, 0x34867077U, 0x30476DC0U,
    0x3D044B19U, 0x39C556AEU, 0x278206ABU, 0x23431B1CU, 0x2E003DC5U, 0x2AC12072U,
    0x128E9DCFU, 0x164F8078U, 0x1B0CA6A1U, 0x1FCDBB16U, 0x018AEB13U, 0x054BF6A4U,
    0x0808D07DU, 0x0CC9CDCAU, 0x7897AB07U, 0x7C56B6B0U, 0x71159069U, 0x75D48DDEU,
    0x6B93DDDBU, 0x6F52C06CU, 0x6211E6B5U, 0x66D0FB02U, 0x5E9F46BFU, 0x5A5E5B08U,
    0x571D7DD1U, 0x53DC6066U, 0x4D9B3063U, 0x495A2DD4U, 0x44190B0DU, 0x40D816BAU,
    0xACA5C697U, 0xA864DB20U, 0xA527FDF9U, 0xA1E6E04EU, 0xBFA1B04BU, 0xBB60ADFCU,
    0xB6238B25U, 0xB2E29692U, 0x8AAD2B2FU, 0x8E6C3698U, 0x832F1041U, 0x87EE0DF6U,
    0x99A95DF3U, 0x9D684044U, 0x902B669DU, 0x94EA7B2AU, 0xE0B41DE7U, 0xE4750050U,
    0xE9362689U, 0xEDF73B3EU, 0xF3B06B3BU, 0xF771768CU, 0xFA325055U, 0xFEF34DE2U,
    0xC6BCF05FU, 0xC27DEDE8U, 0xCF3ECB31U, 0xCBFFD686U, 0xD5B88683U, 0xD1799B34U,
    0xDC3ABDEDU, 0xD8FBA05AU, 0x690CE0EEU, 0x6DCDFD59U, 0x608EDB80U, 0x644FC637U,
    0x7A089632U, 0x7EC98B85U, 0x738AAD5CU, 0x774BB0EBU, 0x4F040D56U, 0x4BC510E1U,
    0x46863638U, 0x42472B8FU, 0x5C007B8AU, 0x58C1663DU, 0x558240E4U, 0x51435D53U,
    0x251D3B9EU, 0x21DC2629U, 0x2C9F00F0U, 0x285E1D47U, 0x36194D42U, 0x32D850F5U,
    0x3F9B762CU, 0x3B5A6B9BU, 0x0315D626U, 0x07D4CB91U, 0x0A97ED48U, 0x0E56F0FFU,
    0x1011A0FAU, 0x14D0BD4DU, 0x19939B94U, 0x1D528623U, 0xF12F560EU, 0xF5EE4BB9U,
    0xF8AD6D60U, 0xFC6C70D7U, 0xE22B20D2U, 0xE6EA3D65U, 0xEBA91BBCU, 0xEF68060BU,
    0xD727BBB6U, 0xD3E6A601U, 0xDEA580D8U, 0xDA649D6FU, 0xC423CD6AU, 0xC0E2D0DDU,
    0xCDA1F604U, 0xC960EBB3U, 0xBD3E8D7EU, 0xB9FF90C9U, 0xB4BCB610U, 0xB07DABA7U,
    0xAE3AFBA2U, 0xAAFBE615U, 0xA7B8C0CCU, 0xA379DD7BU, 0x9B3660C6U, 0x9FF77D71U,
    0x92B45BA8U, 0x9675461FU, 0x8832161AU, 0x8CF30BADU, 0x81B02D74U, 0x857130C3U,
    0x5D8A9099U, 0x594B8D2EU, 0x5408ABF7U, 0x50C9B640U, 0x4E8EE645U, 0x4A4FFBF2U,
    0x470CDD2BU, 0x43CDC09CU, 0x7B827D21U, 0x7F436096U, 0x7200464FU, 0x76C15BF8U,
    0x68860BFDU, 0x6C47164AU, 0x61043093U, 0x65C52D24U, 0x119B4BE9U, 0x155A565EU,
    0x18197087U, 0x1CD86D30U, 0x029F3D35U, 0x065E2082U, 0x0B1D065BU, 0x0FDC1BECU,
    0x3793A651U, 0x3352BBE6U, 0x3E119D3FU, 0x3AD08088U, 0x2497D08DU, 0x2056CD3AU,
    0x2D15EBE3U, 0x29D4F654U, 0xC5A92679U, 0xC1683BCEU, 0xCC2B1D17U, 0xC8EA00A0U,
    0xD6AD50A5U, 0xD26C4D12U, 0xDF2F6BCBU, 0xDBEE767CU, 0xE3A1CBC1U, 0xE760D676U,
    0xEA23F0AFU, 0xEEE2ED18U, 0xF0A5BD1DU, 0xF464A0AAU, 0xF9278673U, 0xFDE69BC4U,
    0x89B8FD09U, 0x8D79E0BEU, 0x803AC667U, 0x84FBDBD0U, 0x9ABC8BD5U, 0x9E7D9662U,
    0x933EB0BBU, 0x97FFAD0CU, 0xAFB010B1U, 0xAB710D06U, 0xA6322BDFU, 0xA2F33668U,
    0xBCB4666DU, 0xB8757BDAU, 0xB5365D03U, 0xB1F740B4U
};

#ifdef CFG_PLATFORM_MCAL
#define FLS_STOP_SEC_CONST_UNSPECIFIED
#include "Fls_MemMap.h"
#endif /* #ifdef CFG_PLATFORM_MCAL */

#ifdef CFG_PLATFORM_MCAL
#define FLS_START_SEC_CODE
#include "Fls_MemMap.h"
#endif /* #ifdef CFG_PLATFORM_MCAL */

/***************************************************************************************************
 *                                  Private Function Declarations                                  *
 **************************************************************************************************/

static inline void Xspi_IpWritel(const Xspi_IpHostType *host, uint32_t addr, uint32_t value)
{
    writel(value, host->config.apbBase + addr);
#if (CONFIG_WITH_XSPI_DEBUG == 2)
    XSPI_LOG_DEBUG("w(0x%x, 0x%08x), r(0x%08x)\n", addr, value, readl(host->config.apbBase + addr));
#endif /* #if (CONFIG_WITH_XSPI_DEBUG == 2) */
}

static inline uint32_t Xspi_IpReadl(const Xspi_IpHostType *host, uint32_t addr)
{
    uint32_t value = readl(host->config.apbBase + addr);
#if (CONFIG_WITH_XSPI_DEBUG == 2)
    XSPI_LOG_DEBUG("r(0x%x, r(0x%08x)\n", addr, value);
#endif /* #if (CONFIG_WITH_XSPI_DEBUG == 2) */
    return value;
}

static inline void Xspi_IpWriteBits(const Xspi_IpHostType *host, uint32_t addr,
                     uint8_t startBit, uint8_t width, uint32_t val)
{
    REG_RMW32(host->config.apbBase + addr, startBit, width, val);
#if (CONFIG_WITH_XSPI_DEBUG == 2)
    XSPI_LOG_DEBUG("wb(0x%x, bit[%d:%d] 0x%08x), r(0x%08x)\n", addr, startBit + width,
                startBit, val, readl(host->config.apbBase + addr));
#endif /* #if (CONFIG_WITH_XSPI_DEBUG == 2) */
}

static void Xspi_IpWriteBitsSafe(const Xspi_IpHostType *host, uint32_t addr,
                     uint8_t startBit, uint8_t width, uint32_t val)
{
    uint32_t reg;
    REG_RMW32(host->config.apbBase + addr, startBit, width, val);
    reg = (((readl(host->config.apbBase + addr) >> startBit) & ((1UL << (width)) - 1U)));
#if (CONFIG_WITH_XSPI_DEBUG == 2)
    XSPI_LOG_DEBUG("wb(0x%x, bit[%d:%d] 0x%08x), r(0x%08x)\n", addr, startBit + width,
                startBit, val, readl(host->config.apbBase + addr));
#endif /* #if (CONFIG_WITH_XSPI_DEBUG == 2) */
    if (val != reg)
    {
        XSPI_LOG_ERROR("Register(0x%x) write safe failed \r\n", addr);
    }
}

static void Xspi_IpWritelSafe(const Xspi_IpHostType *host, uint32_t addr, uint32_t value)
{
    uint32_t reg;
    writel(value, host->config.apbBase + addr);
    reg = (readl(host->config.apbBase + addr)) ^ value;
#if (CONFIG_WITH_XSPI_DEBUG == 2)
    XSPI_LOG_DEBUG("w(0x%x, 0x%08x), r(0x%08x)\n", addr, value, readl(host->config.apbBase + addr));
#endif /* #if (CONFIG_WITH_XSPI_DEBUG == 2) */
    if (0u != reg)
    {
        XSPI_LOG_ERROR("Register(0x%x) write safe failed \r\n", addr);
    }
}

/** *****************************************************************************************************
 * \brief This function Wait for the status of a bit in the register until timeout.
 *
 * \verbatim
 * Syntax             : int32_t Xspi_IpWaitForBitTimes(
 *                          uint32_t reg, const uint32_t mask, bool clear,
 *                          uint32_t times)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Reentrant
 *
 * Parameters (in)    : reg - Register address
 *                      mask - Mask of the wait value
 *                      clear - Inverted or not
 *                      times - Number of timeout cycles
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : 0 - Sucessfully
 *                     !0 - Timeout
 *
 * Description        : Wait for the status of a bit in the register until timeout
 * \endverbatim
 * Traceability       : None
 *******************************************************************************************************/
static int32_t Xspi_IpWaitForBitTimes(uint32_t reg, const uint32_t mask, bool clear,
                          uint32_t times)
{
    uint32_t val;
    uint32_t count = 0;
    int32_t ret = -1;

    while (count < times)
    {
        val = readl(reg);

        if (true == clear)
        {
            val = ~val;
        }

        val &= mask;

        if (val == mask)
        {
            ret = 0;
            break;
        }

        count++;
    }

    return ret;
}

/** *****************************************************************************************************
 * \brief This function returns the log2 of the input value.
 *
 * \verbatim
 * Syntax             : uint8_t Xspi_IpLog2Uint(
 *                          uint64_t val)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Reentrant
 *
 * Parameters (in)    : val - Value to be calculated
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : Calculation results of log2
 *
 * Description        : Returns the calculation result of log2 based on the input value
 * \endverbatim
 * Traceability       : None
 *******************************************************************************************************/
static uint8_t Xspi_IpLog2Uint(uint64_t val)
{
    uint8_t ret = 0;
    uint64_t valTemp = val;

    if (0u != (valTemp & (valTemp - 1U)))
    {
        XSPI_LOG_DEBUG("val is not 2^n\n");
    }

    while (valTemp > 1ULL)
    {
        valTemp >>= 1ULL;
        ret++;
    }

    return ret;
}

/** *****************************************************************************************************
 * \brief This function Wait for control to become idle until timeout.
 *
 * \verbatim
 * Syntax             : int32_t Xspi_IpWaitIdle(
 *                          Xspi_IpHostType *host)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : host - Pointer to controller context
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : 0 - Controlle has been idle
 *                     !0 - Timeout
 *
 * Description        : Wait for control to become idle until timeout.In xip mode,
 *                      this func should to put into iram.
 * \endverbatim
 * Traceability       : SWSR_XSPI_166
 *******************************************************************************************************/
static int32_t Xspi_IpWaitIdle(Xspi_IpHostType *host)
{
    uint32_t idleLatencyCycles = 4;
    uint32_t idleCount = 0;
    uint32_t pollingCycles;
    int32_t ret = XSPI_RET_FAILED;
    uint32_t reg;

    for (pollingCycles = 0; pollingCycles <= XSPI_IP_IDLE_TIMEOUT_CYCLES; pollingCycles++)
    {
        reg = Xspi_IpReadl(host, XSPI_IP_MODE_CTRL);

        if (0U != (reg & XSPI_IP_MODE_CTRL_IDLE))
        {
            idleCount++;
        }
        else
        {
            idleCount = 0;
        }

        /* When IDLE bit asserted, need wait 4 cycyles of refClkHz. */
        if (idleCount >= idleLatencyCycles)
        {
            ret = XSPI_RET_OK;
            break;
        }
    }

    return ret;
}

/** *****************************************************************************************************
 * \brief This function Reset Flash.
 *
 * \verbatim
 * Syntax             : void Xspi_IpResetFlash(
 *                          Xspi_IpHostType *host)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : host - Pointer to controller context
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Reset Flash using controller-controlled hardware IOs
 * \endverbatim
 * Traceability       : None
 *******************************************************************************************************/
static void Xspi_IpResetFlash(Xspi_IpHostType *host)
{
    /* rst enable */
    Xspi_IpWriteBits(host, XSPI_IP_IO_CTRL, XSPI_IP_IO_CTRL_SW_PAD_RST_EN_LSB, 1u, 1U);

    /* rst start */
    Xspi_IpWriteBits(host, XSPI_IP_IO_CTRL, XSPI_IP_IO_CTRL_SW_PAD_RSTN_LSB, 1u, 0U);
    XSPI_UDELAY(1000u);

    /* rst end */
    Xspi_IpWriteBits(host, XSPI_IP_IO_CTRL, XSPI_IP_IO_CTRL_SW_PAD_RSTN_LSB, 1u, 1U);
    XSPI_UDELAY(1000u);

    /* rst disable */
    Xspi_IpWriteBits(host, XSPI_IP_IO_CTRL, XSPI_IP_IO_CTRL_SW_PAD_RST_EN_LSB, 1u, 0U);
    (void) Xspi_IpReadl(host, XSPI_IP_IO_CTRL);
}

/** *****************************************************************************************************
 * \brief This function Configure the RX mode of the controller.
 *
 * \verbatim
 * Syntax             : void Xspi_IpRxModeConfig(
 *                          Xspi_IpHostType *host, uint32_t mode)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : host - Pointer to controller context
 *                      mode - RX mode
 *                              0x0: internal sclk
 *                              0x1: sclk loopback
 *                              0x2: DQS
 *                              0x3: IO loopback dummy DQS
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Configure the RX mode of the controller
 * \endverbatim
 * Traceability       : None
 *******************************************************************************************************/
static void Xspi_IpRxModeConfig(Xspi_IpHostType *host, uint32_t mode)
{
    uint32_t reg;

    XSPI_LOG_DEBUG("RX SEL = %d \r\n", mode);

    reg = Xspi_IpReadl(host, XSPI_IP_SCLK_CTRL);
    reg &= ~(XSPI_IP_SCLK_CTRL_RX_SEL_MASK << XSPI_IP_SCLK_CTRL_RX_SEL_LSB);
    reg |= mode << XSPI_IP_SCLK_CTRL_RX_SEL_LSB;
    Xspi_IpWritel(host, XSPI_IP_SCLK_CTRL, reg);
}

static uint32_t Xspi_IpGetRxMode(Xspi_IpHostType *host)
{
    uint32_t reg = Xspi_IpReadl(host, XSPI_IP_SCLK_CTRL);
    return ((reg >> XSPI_IP_SCLK_CTRL_RX_SEL_LSB) & XSPI_IP_SCLK_CTRL_RX_SEL_MASK);
}

/** *****************************************************************************************************
 * \brief This function Configuring the DLL for the receive channel.
 *
 * \verbatim
 * Syntax             : void Xspi_IpDllEnable(
 *                          Xspi_IpHostType *host, int32_t dllNum, uint32_t value,
 *                          bool enable)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : host - Pointer to controller context
 *                      overrideEnable - Use override mode of DLL
 *                      dllNum - Channel number of DLL
 *                      value - The value of delay chain
 *                      enable - Switch of enable DLL
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Configuring the DLL for the receive channel.
 *                      In xip mode, this func should to put into iram.
 * \endverbatim
 * Traceability       : None
 *******************************************************************************************************/
static void Xspi_IpDllEnable(Xspi_IpHostType *host, bool overrideEnable, int32_t dllNum, uint32_t value,
                     bool enable)
{
    uint32_t reg;
    uint32_t addr;

    addr = (1 == dllNum) ? XSPI_IP_DLL1_CTRL : XSPI_IP_DLL_CTRL;

    if (true == enable)
    {
        (void) Xspi_IpWritelSafe(host, addr, 0u);
        if (true == overrideEnable)
        {
            XSPI_LOG_DEBUG("dll%d enable override mode: 0x%x\r\n", dllNum, value);
            reg = value << XSPI_IP_DLL_CTRL_OVERRIDE_VAL_LSB;
            Xspi_IpWritelSafe(host, addr, reg);
            reg |= LS_IP_DLL_CTRL_OVERRIDE_ENABLE;
            Xspi_IpWritelSafe(host, addr, reg);
        }
        else
        {
            XSPI_LOG_DEBUG("dll%d enable lock mode: 0x%x\r\n", dllNum, value);
            reg = value << XSPI_IP_DLL_CTRL_SLV_TARGET_LSB;
            Xspi_IpWritelSafe(host, addr, reg);
            reg |= XSPI_IP_DLL_CTRL_LOCK_ENABLE;
            Xspi_IpWritelSafe(host, addr, reg);

            if (0 != Xspi_IpWaitForBitTimes(host->config.apbBase + addr + 4U, XSPI_IP_STATUS_SLV_LOCK, false,
                                        XSPI_IP_DLL_ENABLE_TIMEOUT_CYCLES))
            {
                XSPI_LOG_DEBUG("dll%d enable err\r\n", dllNum);
            }
        }
    }

    Xspi_IpWriteBitsSafe(host, XSPI_IP_MODE_CTRL, XSPI_IP_MODE_CTRL_SW_RST_LSB, 1u, 1U);
    XSPI_UDELAY(1);
    Xspi_IpWriteBitsSafe(host, XSPI_IP_MODE_CTRL, XSPI_IP_MODE_CTRL_SW_RST_LSB, 1u, 0U);
    (void) Xspi_IpWaitIdle(host);

    /* set dll_en */
    Xspi_IpWriteBitsSafe(host, XSPI_IP_SCLK_CTRL, XSPI_IP_SCLK_CTRL_DLL_EN_LSB, 1u,
                    (true == enable) ? 1U : 0U);
}

/** *****************************************************************************************************
 * \brief This function Configuring the Controller's Cache.
 *
 * \verbatim
 * Syntax             : void Xspi_IpPrefetchConfig(
 *                          Xspi_IpHostType *host, uint32_t channel,
 *                          uint16 gidMask, uint16 gidMatch,
 *                          uint32_t dataBlock)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : host - Pointer to controller context
 *                      channel - The id of cache channel
 *                      gidMask - The group id mask
 *                      gidMatch - The match value of group id
 *                      dataBlock - Prefetch data block size type
 *
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Configuring the Controller's Cache
 * \endverbatim
 * Traceability       : None
 *******************************************************************************************************/
static void Xspi_IpPrefetchConfig(Xspi_IpHostType *host, uint32_t channel,
                                 uint16 gidMask, uint16 gidMatch,
                                 uint32_t dataBlock)
{
    uint32_t reg;

    if (0u != dataBlock)
    {
        Xspi_IpWritel(host, XSPI_IP_GID_MASK + (0x10U * channel), gidMask);
        Xspi_IpWritel(host, XSPI_IP_GID_MATCH + (0x10U * channel), gidMatch);

        reg = Xspi_IpLog2Uint((uint64)dataBlock >> (4U + XSPI_IP_RBUF_BUFFER_MODE));
        reg = reg << XSPI_IP_RBUF_CTRL_ENTRY_NUM_LSB;
        reg |= (uint32_t)1u << XSPI_IP_RBUF_CTRL_PREFETCH_EN_LSB;
        Xspi_IpWritel(host, XSPI_IP_RBUF_CTRL + (0x10U * channel), reg);
    }
    else
    {
        Xspi_IpWritel(host, XSPI_IP_GID_MASK + (0x10U * channel), 0u);
        Xspi_IpWritel(host, XSPI_IP_GID_MATCH + (0x10U * channel), 0u);
        Xspi_IpWritel(host, XSPI_IP_RBUF_CTRL + (0x10U * channel), 0u);
    }
}

/** *****************************************************************************************************
 * \brief This function Open and initialise the cache for all channels.
 *
 * \verbatim
 * Syntax             : void Xspi_IpPrefetchEnable(
 *                          Xspi_IpHostType *host)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : host - Pointer to controller context
 *                      enable - Switch of the prefetch
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Open and initialise the cache for all channels.
 *                      In xip mode, this func should to put into iram.
 * \endverbatim
 * Traceability       : None
 *******************************************************************************************************/
static void Xspi_IpPrefetchEnable(Xspi_IpHostType *host, bool enable)
{
    uint8_t i;
    Xspi_IpWriteBits(host, XSPI_IP_AXI_CTRL, XSPI_IP_TIMEOUT_BRESP_MODE_LSB, 1U, 1U);

    /* Group 0 is common */
    for (i = 0u; i < XSPI_IP_RBUF_CHANNEL_NUM; i++)
    {
        Xspi_IpPrefetchConfig(host, i, Xspi_IpRbufGidMask[i], Xspi_IpRbufGidMatch[i], (true == enable) ? 128u : 0u);
    }
    Xspi_IpWriteBits(host, XSPI_IP_MODE_CTRL, XSPI_IP_MODE_CTRL_RBUF_MODE_SEL_LSB, 1u,
        (true == enable) ? XSPI_IP_RBUF_BUFFER_MODE : 0u);
}

/** *****************************************************************************************************
 * \brief This function Flush the controller's cache.
 *
 * \verbatim
 * Syntax             : void Xspi_IpPrefetchFlush(
 *                          Xspi_IpContextType *host)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : host - Pointer to controller context
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Flush the controller's cache
 * \endverbatim
 * Traceability       : None
 *******************************************************************************************************/
static void Xspi_IpPrefetchFlush(Xspi_IpHostType *host)
{
    uint32_t channel;

    for (channel = 0u; channel < XSPI_IP_RBUF_CHANNEL_NUM; channel++) {
        Xspi_IpWriteBits(host, XSPI_IP_RBUF_CTRL + (0x10U * channel), XSPI_IP_RBUF_CTRL_FLUSH_LSB, 1U, 1U);
        Xspi_IpWriteBits(host, XSPI_IP_RBUF_CTRL + (0x10U * channel), XSPI_IP_RBUF_CTRL_FLUSH_LSB, 1U, 0U);
    }
}

/** *****************************************************************************************************
 * \brief This function Configure the controller delay.
 *
 * \verbatim
 * Syntax             : void Xspi_IpDelaySetup(
 *                          Xspi_IpHostType *host)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : host - Pointer to IP handler
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Configure the controller delay such as cs setup and hold times etc.
 * \endverbatim
 * Traceability       : None
 *******************************************************************************************************/
static void Xspi_IpDelaySetup(Xspi_IpHostType *host)
{
    uint32_t reg, tslch, tshsl, tchsh;

    tslch = XSPI_IP_NS_2_TICKS(host->currentRefClkHz, 10U);
    tshsl = XSPI_IP_NS_2_TICKS(host->currentRefClkHz, 30U);
    tchsh = XSPI_IP_NS_2_TICKS(host->currentRefClkHz, 10U);
    tchsh = (tchsh >= 3U) ? tchsh : 3U;
    /* Errata 3.3.5: error AES decoded data.
     *  SHSL_TIME + CSH_TIME >= 11
     */
    tshsl = ((tshsl + tchsh) >= 11u) ? tshsl : (11u - tchsh);

    reg = Xspi_IpReadl(host, XSPI_IP_CS_CTRL);
    reg &= ~(XSPI_IP_CS_CTRL_TIME_DELAY_MASK << XSPI_IP_CS_CTRL_TSLCH_LSB);
    reg |= (uint32_t)(tslch & XSPI_IP_CS_CTRL_TIME_DELAY_MASK) << XSPI_IP_CS_CTRL_TSLCH_LSB;

    reg &= ~(XSPI_IP_CS_CTRL_TIME_SHSL_DELAY_MASK << XSPI_IP_CS_CTRL_TSHSL_LSB);
    reg |= (uint32_t)(tshsl & XSPI_IP_CS_CTRL_TIME_SHSL_DELAY_MASK) << XSPI_IP_CS_CTRL_TSHSL_LSB;

    reg &= ~(XSPI_IP_CS_CTRL_TIME_DELAY_MASK << XSPI_IP_CS_CTRL_TCHSH_LSB);
    reg |= (uint32_t)(tchsh & XSPI_IP_CS_CTRL_TIME_DELAY_MASK) << XSPI_IP_CS_CTRL_TCHSH_LSB;

    Xspi_IpWritel(host, XSPI_IP_CS_CTRL, reg);
}

static void Xspi_IpCmdSetup(Xspi_IpHostType *host, Xspi_IpCmdSetupType type,
    Xspi_IpCommandType *cmd)
{
    Xspi_IpRdWrPhaseCtrlType phReg;
    uint16_t opcode = cmd->proto.detail.opcode;
    uint8_t dummy = cmd->dummy;

    phReg.reg = 0u;

    phReg.data.cLine = cmd->proto.detail.comandLans;
    phReg.data.aLine = cmd->proto.detail.addressLans;
    phReg.data.dLine = cmd->proto.detail.dataLans;
    phReg.data.cEn = 1u;
    phReg.data.dEn = (1u == cmd->proto.detail.dataDis) ? 0u : 1u;

    if ((cmd->proto.detail.addressDis == 0u) && (cmd->addrBytes != 0u))
    {
        phReg.data.aEn = 1u;
        phReg.data.aSize = cmd->addrBytes - 1u;
    }

    phReg.data.cRate = cmd->proto.detail.comamdRate;
    phReg.data.aRate = cmd->proto.detail.addressRate;
    phReg.data.dRate = cmd->proto.detail.dataRate;
    phReg.data.cSize = phReg.data.cRate;

    if (cmd->proto.detail.invertOpcodeEn != 0u)
    {
        opcode |=  (((~opcode) & 0xFFu) << 8);
    }
    else
    {
        opcode |=  (opcode << 8);
    }

    if ((XSPI_IP_HYPERRAM == host->config.devType) && (dummy != 0u))
    {
        /* For hyperram, e3 xspi's dummy is device spec's dummy + 1 */
        dummy++;
    }

    switch (type)
    {
    case XSPI_IP_DIRECR_READ:
        Xspi_IpWritel(host, XSPI_IP_DIRECT_RD_PH_CTRL, phReg.reg);
        Xspi_IpWriteBits(host, XSPI_IP_DIRECT_C_CODE, XSPI_IP_DIRECT_C_CODE_RCODE_LSB,
                            16U, opcode);
        Xspi_IpWriteBits(host, XSPI_IP_DIRECT_D_CYC, XSPI_IP_DIRECT_D_CYC_RD_LSB,
                            5U, dummy);
        break;
    case XSPI_IP_DIRECR_WRITE: /* For hyperram */
        Xspi_IpWritel(host, XSPI_IP_DIRECT_WR_PH_CTRL, phReg.reg);
        Xspi_IpWriteBits(host, XSPI_IP_DIRECT_C_CODE, XSPI_IP_DIRECT_C_CODE_WCODE_LSB,
                        16U, opcode);
        Xspi_IpWriteBits(host, XSPI_IP_DIRECT_D_CYC, XSPI_IP_DIRECT_D_CYC_WR_LSB,
                        5U, dummy);
        /* hyperram mode not need write enable */
        Xspi_IpWriteBits(host, XSPI_IP_DIRECT_WREN, XSPI_IP_DIRECT_WREN_LSB, 1u, 0u);
        break;
    case XSPI_IP_INDIRECR_READ:
        if (cmd->proto.detail.modeBitEn != 0u)
        {
            phReg.data.mRate = cmd->proto.detail.addressRate;
            phReg.data.mLine = cmd->proto.detail.addressLans;
            phReg.data.mSize = 1u;
            phReg.data.mEn = 1u;
            Xspi_IpWritel(host, XSPI_IP_INDIRECT_RD_M_CODE, cmd->modeCode);
        }
        Xspi_IpWritel(host, XSPI_IP_INDIRECT_RD_PH_CTRL, phReg.reg);
        Xspi_IpWritel(host, XSPI_IP_INDIRECT_RD_CMD_CODE, opcode);
        Xspi_IpWritel(host, XSPI_IP_INDIRECT_RD_CYC, dummy);
        break;
    case XSPI_IP_INDIRECR_WRITE:
        Xspi_IpWritel(host, XSPI_IP_INDIRECT_WR_PH_CTRL, phReg.reg);
        Xspi_IpWritel(host, XSPI_IP_INDIRECT_WR_CMD_CODE, opcode);
        Xspi_IpWritel(host, XSPI_IP_INDIRECT_WR_CYC, dummy);
        break;
    default:
        /* Do nothing */
        break;
    }
}

static void Xspi_IpCmdAcquire(Xspi_IpHostType *host, Xspi_IpCmdSetupType type,
    Xspi_IpCommandType *cmd)
{
    Xspi_IpRdWrPhaseCtrlType phReg = { 0 };
    uint16_t opcode = 0u;

    switch (type)
    {
    case XSPI_IP_DIRECR_READ:
        phReg.reg = Xspi_IpReadl(host, XSPI_IP_DIRECT_RD_PH_CTRL);
        opcode = (uint16_t)(Xspi_IpReadl(host, XSPI_IP_DIRECT_C_CODE) & XSPI_IP_DIRECT_C_CODE_MASK);
        cmd->dummy = (uint8_t)(Xspi_IpReadl(host, XSPI_IP_DIRECT_D_CYC) & XSPI_IP_DIRECT_D_CYC_RD_MASK);
        break;
    case XSPI_IP_INDIRECR_WRITE:
        phReg.reg = Xspi_IpReadl(host, XSPI_IP_INDIRECT_WR_PH_CTRL);
        opcode = (uint16_t)(Xspi_IpReadl(host, XSPI_IP_INDIRECT_WR_CMD_CODE) & XSPI_IP_INDIRECT_WR_CMD_CODE_MASK);
        cmd->dummy = (uint8_t)(Xspi_IpReadl(host, XSPI_IP_INDIRECT_WR_CYC) & XSPI_IP_INDIRECT_WR_CYC_MASK);
        break;
    default:
        XSPI_LOG_ERROR("Xspi_IpCmdAcquire unsupport type %d\r\n", type);
        break;
    }

    if ((XSPI_IP_HYPERRAM == host->config.devType) && (cmd->dummy > 1u))
    {
        cmd->dummy--;
    }

    cmd->addrBytes = phReg.data.aSize + 1u;
    cmd->proto.detail.dataLans = phReg.data.dLine;
    cmd->proto.detail.dataDis = 0u;
    cmd->proto.detail.dataRate = phReg.data.dRate;
    cmd->proto.detail.addressLans = phReg.data.aLine;
    cmd->proto.detail.addressDis = 0u;
    cmd->proto.detail.addressRate = phReg.data.aRate;
    cmd->proto.detail.comandLans = phReg.data.cLine;
    cmd->proto.detail.comamdRate = phReg.data.cRate;
    cmd->proto.detail.modeBitEn = 0u;
    cmd->proto.detail.invertOpcodeEn = (((~opcode) & 0xFFu) == ((opcode >> 8) & 0xFFu)) ? 1u: 0u;
    cmd->proto.detail.opcode = opcode & 0xFFu;
}

static void Xspi_IpGetProto(Xspi_IpHostType *host)
{
    Xspi_IpCmdAcquire(host, XSPI_IP_INDIRECR_WRITE, &host->memoryWriteCmd);
    Xspi_IpCmdAcquire(host, XSPI_IP_DIRECR_READ, &host->memoryReadCmd);
}

/** *****************************************************************************************************
 * \brief This function Trigger indirect access.
 *
 * \verbatim
 * Syntax             : void Xspi_IpIndirectTrigger(
 *                          Xspi_IpHostType *host, uint32_t addr
 *                          uint32_t size, int32_t flag)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : host - Pointer to controller Context
 *                      addr - Address in flash memory
 *                      size - Buffer size
 *                      flag - Read or Write flag
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Trigger indirect access
 * \endverbatim
 * Traceability       : None
 *******************************************************************************************************/
static void Xspi_IpIndirectTrigger(Xspi_IpHostType *host, uint32_t addr,
                           uint32_t size, Xspi_IpCmdSetupType flag)
{
    if (flag == XSPI_IP_INDIRECR_READ)
    {
        /* Set indirect read start address */
        Xspi_IpWritel(host, XSPI_IP_INDIRECT_RD_ADDR, addr);
        /* Set indirect read bytes number */
        Xspi_IpWritel(host, XSPI_IP_INDIRECT_RD_SIZE, size);
        /* Start the indirect read */
        Xspi_IpWritel(host, XSPI_IP_INDIRECT_RD_CTRL, 1u);
    }
    else
    {
        /* Set indirect write start address */
        Xspi_IpWritel(host, XSPI_IP_INDIRECT_WR_ADDR, addr);
        /* Set indirect write bytes number */
        Xspi_IpWritel(host, XSPI_IP_INDIRECT_WR_SIZE, size);
        /* Start the indirect write */
        Xspi_IpWritel(host, XSPI_IP_INDIRECT_WR_CTRL, 1u);
    }
}

static int32_t Xspi_IpTxFifoTransfer(Xspi_IpHostType *host, const uint8_t* buf, uint32_t size)
{
    int32_t ret = XSPI_RET_FAILED;
    const uint32_t *u32Ptr;
    uint32_t alignedSize;
    uint32_t unalingedSize;
    uint32_t tempData = 0u;
    uint32_t fifoAddress = host->config.apbBase + XSPI_IP_INDIRECT_WDATA;

    if (XSPI_IS_ALIGNED(buf, 4u))
    {
        /* PRQA S 3305 1 */
        u32Ptr = (const uint32_t*)buf;
        alignedSize = size >> 2;
        unalingedSize = size % 4u;

        while (alignedSize > 0u)
        {
            writel(*u32Ptr, fifoAddress);
            u32Ptr++;
            alignedSize--;
        }

        if (unalingedSize > 0u)
        {
            (void) Xspi_Memcopy((void*)&tempData, (const void*)&buf[size - unalingedSize], unalingedSize);
            writel(tempData, fifoAddress);
        }
        ret = XSPI_RET_OK;
    }
    return ret;
}

static int32_t Xspi_IpRxFifoTransfer(Xspi_IpHostType *host, uint8_t* buf, uint32_t size)
{
    int32_t ret = XSPI_RET_FAILED;
    uint32_t *u32Ptr;
    uint32_t alignedSize;
    uint32_t unalingedSize;
    uint32_t tempData;
    uint32_t fifoAddress = host->config.apbBase + XSPI_IP_INDIRECT_RDATA;

    if (XSPI_IS_ALIGNED(buf, 4u))
    {
        /* PRQA S 3305 1 */
        u32Ptr = (uint32_t*)buf;
        alignedSize = size >> 2;
        unalingedSize = size % 4u;

        while (alignedSize > 0u)
        {
            *u32Ptr = readl(fifoAddress);
            u32Ptr++;
            alignedSize--;
        }

        if (unalingedSize > 0u)
        {
            tempData = readl(fifoAddress);
            (void) Xspi_Memcopy((void*)&buf[size - unalingedSize], (const void*)&tempData, unalingedSize);
        }
        ret = XSPI_RET_OK;
    }
    return ret;
}

/** *****************************************************************************************************
 * \brief This function Wait for reception to complete until timeout.
 *
 * \verbatim
 * Syntax             : int32_t Xspi_IpRxComplete(
 *                          Xspi_IpHostType *host)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : host - Pointer to controller context
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Wait for reception to complete until timeout
 * \endverbatim
 * Traceability       : None
 *******************************************************************************************************/
static int32_t Xspi_IpRxComplete(Xspi_IpHostType *host)
{
    int32_t ret;

    ret = Xspi_IpWaitForBitTimes(host->config.apbBase + XSPI_IP_INT_ST_FUC,
                                XSPI_IP_INT_ST_FUC_INDIRECT_RD_DONE,
                                false, XSPI_IP_READ_DONE_TIMEOUT_CYCLES);

    if (ret != 0)
    {
        XSPI_LOG_DEBUG("Indirect read not complete, ret %d.\n", ret);
    }
    else
    {
        Xspi_IpWritel(host, XSPI_IP_INT_ST_FUC, XSPI_IP_INT_ST_FUC_INDIRECT_RD_DONE);
    }
    Xspi_IpWriteBits(host, XSPI_IP_INDIRECT_RX_BUF, XSPI_IP_INDIRECT_RX_BUF_FLUSH_LSB, 1u, 1u);

    return ret;
}

/** *****************************************************************************************************
 * \brief This function Wait for the send to complete until it times out.
 *
 * \verbatim
 * Syntax             : int32_t Xspi_IpTxComplete(
 *                          Xspi_IpContextType *host)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : host - Pointer to controller context
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Wait for the send to complete until it times out
 * \endverbatim
 * Traceability       : None
 *******************************************************************************************************/
static int32_t Xspi_IpTxComplete(Xspi_IpHostType *host)
{
    int32_t ret;

    ret = Xspi_IpWaitForBitTimes(host->config.apbBase + XSPI_IP_INT_ST_FUC,
                                XSPI_IP_INT_ST_FUC_INDIRECT_WR_DONE,
                                false, XSPI_IP_WRITE_DONE_TIMEOUT_CYCLES);

    if (ret != 0)
    {
        XSPI_LOG_DEBUG("Indirect write not complete, ret %d.\n", ret);
    }
    else
    {
        Xspi_IpWritel(host, XSPI_IP_INT_ST_FUC, XSPI_IP_INT_ST_FUC_INDIRECT_WR_DONE);
    }
    Xspi_IpWriteBits(host, XSPI_IP_INDIRECT_TX_BUF, XSPI_IP_INDIRECT_TX_BUF_FLUSH_LSB, 1u, 1u);

    return ret;
}

/** *****************************************************************************************************
 * \brief This function Get the amount of data received in the Buffer in the controller.
 *
 * \verbatim
 * Syntax             : uint32_t Xspi_IpGetReceiveBufLevel(
 *                          Xspi_IpHostType *host)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : host - Pointer to controller context
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : The amount of data received
 *
 * Description        : Get the amount of data received in the Buffer in the controller
 * \endverbatim
 * Traceability       : None
 *******************************************************************************************************/
static uint32_t Xspi_IpGetReceiveBufLevel(Xspi_IpHostType *host)
{
    uint32_t reg = Xspi_IpReadl(host, XSPI_IP_INDIRECT_RX_BUF);
    reg >>= XSPI_IP_INDIRECT_RX_BUF_ENTRY_LSB;
    return reg & XSPI_IP_INDIRECT_RX_BUF_ENTRY_MASK;
}

/** *****************************************************************************************************
 * \brief This function Get the amount of data sent to the Buffer in the controller.
 *
 * \verbatim
 * Syntax             : uint32_t Xspi_IpGetWriteBufLevel(
 *                          Xspi_IpContextType *host)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : host - Pointer to controller context
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : The amount of data received
 *
 * Description        : Get the amount of data sent to the Buffer in the controller
 * \endverbatim
 * Traceability       : None
 *******************************************************************************************************/
static uint32_t Xspi_IpGetWriteBufLevel(Xspi_IpHostType *host)
{
    uint32_t reg = Xspi_IpReadl(host, XSPI_IP_INDIRECT_TX_BUF);
    reg >>= XSPI_IP_INDIRECT_TX_BUF_ENTRY_LSB;
    return reg & XSPI_IP_INDIRECT_TX_BUF_ENTRY_MASK;
}

static int32_t Xspi_IpFifoRead(Xspi_IpHostType *host, uint8_t* buf, uint32_t size)
{
    uint32_t readDone = 0u;
    uint32_t timeoutCnt = size * XSPI_IP_XFER_POLLING_TIMEOUT;
    uint32_t bytesReady;

    while ((readDone < size) && (timeoutCnt > 0u))
    {
        bytesReady = Xspi_IpGetReceiveBufLevel(host) << 2;
        bytesReady = XSPI_MIN(bytesReady, size - readDone);
        if (bytesReady > 0u)
        {
            if (XSPI_RET_OK != Xspi_IpRxFifoTransfer(host, &buf[readDone], bytesReady))
            {
                break;
            }
            readDone += bytesReady;
        }

        timeoutCnt--;
    }

    return (readDone < size) ? XSPI_RET_FAILED : XSPI_RET_OK;
}

static int32_t Xspi_IpFifoWrite(Xspi_IpHostType *host, const uint8_t* buf, uint32_t size)
{
    uint32_t writeDone = 0u;
    uint32_t timeoutCnt = size * XSPI_IP_XFER_POLLING_TIMEOUT;
    uint32_t bytesPending;
    uint32_t writeSize;

    while ((writeDone < size) && (timeoutCnt > 0u))
    {
        bytesPending = Xspi_IpGetWriteBufLevel(host);
        if (bytesPending == 0u)
        {
            writeSize = XSPI_MIN(size - writeDone, host->config.fifoSize);
            if (XSPI_RET_OK != Xspi_IpTxFifoTransfer(host, &buf[writeDone], writeSize))
            {
                break;
            }
            writeDone += writeSize;
        }

        timeoutCnt--;
    }

    return (writeDone < size) ? XSPI_RET_FAILED : XSPI_RET_OK;
}

static int32_t Xspi_IpFifoPreWrite(Xspi_IpHostType *host, const uint8_t *buf, uint32_t size)
{
    int32_t ret = XSPI_RET_FAILED;

    if (size > host->config.fifoSize)
    {
        /* Do nothing */
    }
    else
    {
        ret = Xspi_IpFifoWrite(host, buf, size);
    }
    return ret;
}

static uint32_t Xspi_IpCrc32(uint32_t crcBegin, uint8_t const *buffer, uint32_t len)
{
    uint32_t crc = crcBegin;
    uint32_t length = len;
    uint8_t const *bufPtr = buffer;
    crc ^= 0xFFFFFFFFUL;

    while (0U != length)
    {
        crc = (crc << 8) ^ Xspi_IpCrc32Table[(crc >> 24) ^ (*bufPtr)];
        length--;
        bufPtr++;
    }

    return crc ^ 0xFFFFFFFFUL;
}

static uint8_t Xspi_IpRfdCheck(Xspi_IpHostType *host)
{
    uint8_t enableMask = 0U;
    uint8_t i;
    Xspi_IpRfdRegionType rfdBuffer;

    (void) Xspi_IpMemoryRead(host, XSPI_IP_RFD_START_ADDRESS,
            (uint8_t *)&rfdBuffer, sizeof(Xspi_IpRfdRegionType));
    for (i = 0; i < XSPI_IP_MAX_RFD_REGION; i++)
    {
        if (rfdBuffer.crc[i] ==
                Xspi_IpCrc32(0, rfdBuffer.rfd[i], XSPI_IP_RFD_LENGTH))
        {
            enableMask |= (1U << i);
        }
    }

    return enableMask;
}

/** *****************************************************************************************************
 * \brief This function Configure the controller firewall region.
 *
 * \verbatim
 * Syntax             : int32_t Xspi_IpAddFirewallRegion(
 *                          Xspi_IpHostType *host, uint32_t addr,
 *                          uint32_t size, uint8 *regionId)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : host - Pointer to flash context
 *                      addr - Firewall region's start address
 *                      size - The size of firewall region
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : regionId - Region index
 *
 * Return value       : 0 - Sucessfully
 *                     !0 - Failed
 *
 * Description        : Configure the controller firewall region
 * \endverbatim
 * Traceability       : None
 *******************************************************************************************************/
static int32_t Xspi_IpAddFirewallRegion(Xspi_IpHostType *host, uint32_t addr, uint32_t size, uint8 *regionId)
{
    int32_t ret = XSPI_RET_FAILED;
    uint8 region = 0;
    uint32 regionAddress, regionSize, reg1, reg2;
    uint8 cs;
    uint32 csOffset = 0u;

    for (cs = 0u; cs < 2u; cs++)
    {
        if ((addr >= csOffset) &&
            ((addr + size) <= (host->devSize[cs] + csOffset)))
        {
            break;
        }
        csOffset += host->devSize[cs];
    }
    if (cs < 2u)
    {
        regionAddress = (addr >> 12) & XSPI_IP_PROT_ADDR_MASK;
        regionSize = (size >> 12) & XSPI_IP_PROT_RANGE_MASK;
        regionAddress |= ((uint32)cs << XSPI_IP_PROT_CS_LSB);

        while (region < XSPI_IP_PROT_REGION_MAX_NUM)
        {
            reg1 = Xspi_IpReadl(host, XSPI_IP_PROT_ADDR_REG + ((uint32)region * 4U)) & XSPI_IP_PROT_ADDR_CS_MASK;
            reg2 = Xspi_IpReadl(host, XSPI_IP_PROT_RANGE_REG + ((uint32)region * 4U)) & XSPI_IP_PROT_RANGE_MASK;

            if ((0u != reg1) || (0u != reg2))
            {
                /* RegionX has been added */
                if ((reg1 != regionAddress) || (reg2 != regionSize))
                {
                    /* Regional configurations and current are not the same */
                    region++;
                    continue;
                }
                XSPI_LOG_DEBUG("FW region-%d has been configured to (%x %x)\n",
                    region, regionAddress, regionSize);
            }
            else
            {
                /* Add a fw region configuration */
                Xspi_IpWritel(host, XSPI_IP_PROT_ADDR_REG + ((uint32)region * 4u), regionAddress);
                Xspi_IpWritel(host, XSPI_IP_PROT_RANGE_REG + ((uint32)region * 4u), regionSize);
                XSPI_LOG_DEBUG("FW region-%d is configured to (%x %x)\n",
                    region, regionAddress, regionSize);
            }
            ret = XSPI_RET_OK;
            *regionId = region;
            break;
        }
    }

    return ret;
}

/** *****************************************************************************************************
 * \brief This function Configure the controller firewall access.
 *
 * \verbatim
 * Syntax             : int32_t Xspi_IpFirewallAccessConfig(
 *                          Xspi_IpHostType *host, uint8 regionId,
 *                          Xspi_IpFwConfigType *config)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : host - Pointer to flash context
 *                      regionId - Region index
 *                      config - The configuration of firewall access
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : regionId - Region index
 *
 * Return value       : 0 - Sucessfully
 *                     !0 - Failed
 *
 * Description        : Configure the controller firewall access
 * \endverbatim
 * Traceability       : None
 *******************************************************************************************************/
static int32_t Xspi_IpFirewallAccessConfig(Xspi_IpHostType *host, uint8 regionId,
                                Xspi_IpFwConfigType const *config)
{
    int32_t ret = XSPI_RET_OK;
    uint32 perRegAddress;
    uint8_t regProtMask;

    if ((NULL == config) ||
        (regionId >= XSPI_IP_PROT_REGION_MAX_NUM) ||
        (config->masterId > XSPI_IP_WR_RD_PROT_PER_MID_MASK))
    {
        XSPI_LOG_DEBUG("Config invilid\n");
        ret = XSPI_RET_PARAMETER_ERR;
    }
    else
    {
        if (XSPI_IS_P0) {
            regProtMask = 0xFu;
        }
        else {
            regProtMask = ((config->protId & 0x1u) == 0u) ? 0x5u : 0xAu;
        }

        if ((XSPI_IP_FW_DIR_BOTH_WR_RD == config->direct) ||
            (XSPI_IP_FW_DIR_ONLY_WR == config->direct))
        {
            perRegAddress = XSPI_IP_WR_PROT_PER_EN_REG + ((uint32)regionId * 8u) +
                    (((config->masterId & 0x8u) != 0u) ? 4u : 0u);
            Xspi_IpWriteBits(host, perRegAddress, (config->masterId & 0x7u) * 4u, 4u, regProtMask);
            XSPI_LOG_DEBUG("Region-%d Cfg(%x %x)\n", regionId, perRegAddress, Xspi_IpReadl(host, perRegAddress));
        }

        if ((XSPI_IP_FW_DIR_BOTH_WR_RD == config->direct) ||
            (XSPI_IP_FW_DIR_ONLY_RD == config->direct))
        {
            perRegAddress = XSPI_IP_RD_PROT_PER_EN_REG + ((uint32)regionId * 8u) +
                            (((config->masterId & 0x8u) != 0u) ? 4u : 0u);
            Xspi_IpWriteBits(host, perRegAddress, (config->masterId & 0x7u) * 4u, 4u, regProtMask);
            XSPI_LOG_DEBUG("Region-%d Cfg(%x %x)\n", regionId, perRegAddress, Xspi_IpReadl(host, perRegAddress));
        }
    }
    return ret;
}

/***************************************************************************************************
 *                                  Global Function Declarations                                   *
 **************************************************************************************************/
void* Xspi_Memcopy(void *dst, const void *src, uint32_t totalSize)
{
    uint32_t size = totalSize;
    uint32_t alignSrc = (uint32_t)src % 4UL;
    uint32_t alignDst = (uint32_t)dst % 4UL;
    uint8_t *dstPtr = (uint8_t *)dst;
    const uint8_t *srcPtr = (const uint8_t *)src;
    uint32_t i;
    uint32_t bytes;

    if (alignSrc != alignDst) {
        for (; size > 0u; size--) {
            *dstPtr = *srcPtr;
            ++dstPtr;
            ++srcPtr;
        }
    } else {
        if (0u != alignSrc) {
            bytes = (size > (4u - alignDst)) ? (4u - alignDst) : size;

            for (i = 0u; i < bytes ; i++) {
                *dstPtr = *srcPtr;
                --size;
                ++dstPtr;
                ++srcPtr;
            }
        }

        if (size > 4u) {
            bytes = size / 4u * 4u;
            (void) Xspi_4BytesAlignedMemcpy((void*)dstPtr, (const void*)srcPtr, bytes);
            dstPtr += bytes;
            srcPtr += bytes;
            size -= bytes;
        }

        for (; size > 0u; size--) {
            *dstPtr = *srcPtr;
            ++dstPtr;
            ++srcPtr;
        }
    }
    return dst;
}

int32_t Xspi_IpInit(Xspi_IpHostType *host, const Xspi_IpHostConfigType *config)
{
    int32_t ret = XSPI_RET_OK;

    /* PRQA S 0315 1 */
    (void)XSPI_MEMCLR(host, sizeof(Xspi_IpHostType));

    (void) Xspi_Memcopy((void*)&host->config, (const void*)&config->config, sizeof(Xspi_IpHostStaticConfigType));
    host->prefetchEnable = config->prefetchEnable;
    host->useDummyRead = config->useDummyRead;
    host->rfdEnable = config->rfdEnable;
    host->currentRefClkHz = 0u;
    host->dqsEnable = false;

    if (host->config.useRomConfig == true)
    {
        host->currentRefClkHz = config->config.refClkHz;
        host->dqsEnable = (Xspi_IpGetRxMode(host) == 0x2u) ? true : false;
        Xspi_IpGetProto(host);
    }
    else if (XSPI_RET_OK != Xspi_IpWaitIdle(host))
    {
        ret = XSPI_RET_BUSY;
    }
    else {
        /* Use rx mode by pop data by deafult */
        Xspi_IpWritel(host, XSPI_IP_MODE_CTRL, XSPI_IP_MODE_CTRL_RX_MODE);

        /* Use sigle device lockstep mode */
        Xspi_IpWriteBits(host, XSPI_IP_MODE_CTRL, XSPI_IP_MODE_CTRL_DEV_LS_LSB, 1u, 1U);

        /* Set immediate=0 for turnaround half of dummy */
        Xspi_IpWriteBits(host, XSPI_IP_MISC, XSPI_IP_MISC_IMMEDIATE_LSB, 1u, 0U);

        /* Set capture enable select to 7 clk period */
        Xspi_IpWriteBits(host, XSPI_IP_MISC, XSPI_IP_MISC_CAPTURE_SEL_LSB, 3U, 0x5U);

        Xspi_IpResetFlash(host);

        /* rx_mode use internal sclk by default */
        Xspi_IpRxModeConfig(host, 0x0);

        /* The default mode of DLL mode is bypass */
        Xspi_IpDllEnable(host, true, 0, 0u, false);
        Xspi_IpDllEnable(host, true, 1, 0u, false);

        (void) Xspi_IpRefclkSetup(host, config->config.refClkHz);
    }

    return ret;
}

int32_t Xspi_IpTraining(Xspi_IpHostType *host, Xspi_IpTrainingCheckCallbackType callBack, void *callBackArg)
{
    int32_t ret = XSPI_RET_FAILED;
    uint32_t rxDelay;
    uint32_t rxDelayStart = 0;
    bool trainOk = false;
    uint32_t trainingSteps;
    bool overrideEn;

    Xspi_IpPrefetchEnable(host, false);

    if ((true == host->dqsEnable) && (host->currentRefClkHz > XSPI_IP_DLL_LOCK_MODE_REFCLK_MIN))
    {
        overrideEn = false;
        rxDelay = XSPI_IP_DLL_LOCKE_MODE_STEP;
        trainOk = true;
    }
    else
    {
#if (XSPI_IP_DLL_USE_LOCK_MODE)
        if (host->currentRefClkHz > XSPI_IP_DLL_LOCK_MODE_REFCLK_MIN)
        {
            overrideEn = false;
            trainingSteps = XSPI_IP_DLL_LOCKE_MODE_STEP;
        }
        else
#endif /* #if (XSPI_IP_DLL_USE_LOCK_MODE) */
        {
            overrideEn = true;
            trainingSteps = XSPI_IP_DLL_OVERRIDE_MODE_STEP;
        }

        for (rxDelay = 0u; rxDelay <= trainingSteps; rxDelay++)
        {
            Xspi_IpDllEnable(host, overrideEn, 0, rxDelay, true);
            Xspi_IpDllEnable(host, overrideEn, 1, rxDelay, true);

            if (XSPI_RET_OK == callBack(callBackArg))
            {
                XSPI_LOG_DEBUG("xspi dll training succeful, rxDelay = 0x%x \r\n", rxDelay);
                if (false == trainOk)
                {
                    trainOk = true;
                    rxDelayStart = rxDelay;
                }
            }
            else
            {
                if ((true == trainOk) && (0u == rxDelayStart) &&
                    (rxDelay > 4u) && (rxDelay < 19u))
                {
                    /* PRQA S 2469 1 */
                    rxDelay = 0u;
                }
                else if ((true == trainOk) && (rxDelay > (rxDelayStart + 10u)))
                {
                    /* Do Nothing */
                }
                else
                {
                    trainOk = false;
                }

                if (true == trainOk)
                {
                    break;
                }
            }

        }
    }

    if (true == trainOk)
    {
        rxDelay = (rxDelayStart + rxDelay) / 2u;
        Xspi_IpDllEnable(host, overrideEn, 0, rxDelay, (rxDelay != 0u) ? true : false);
        Xspi_IpDllEnable(host, overrideEn, 1, rxDelay, (rxDelay != 0u) ? true : false);

        if (XSPI_RET_OK != callBack(callBackArg))
        {
            XSPI_LOG_DEBUG("training read back check failed! Read check again!!\n");
            if (XSPI_RET_OK != callBack(callBackArg))
            {
                XSPI_LOG_DEBUG("xspi phy training failed!\n");
            }
            else
            {
                XSPI_LOG_DEBUG("xspi phy training pass(after try again)!\n");
                ret = XSPI_RET_OK;
            }
        }
        else
        {
            XSPI_LOG_DEBUG("xspi phy training pass!\n");
            ret = XSPI_RET_OK;
        }
    }
    else
    {
        Xspi_IpDllEnable(host, overrideEn, 0, 0u, false);
        Xspi_IpDllEnable(host, overrideEn, 1, 0u, false);
        XSPI_LOG_DEBUG("xspi phy training failed, disable dll!\n");
    }

    if (true == host->prefetchEnable)
    {
        Xspi_IpPrefetchEnable(host, true);
    }

    return ret;
}

/** *****************************************************************************************************
 * \brief This function Implementation of reading data from Flash.
 *
 * \verbatim
 * Syntax             : int32_t Xspi_IpRead(
 *                          Xspi_IpHostType *host, uint32_t addr, uint8_t *buf,
 *                          uint32_t size)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : nor - Pointer to bus handler
 *                      addr - Physical address of Flash
 *                      buf - buffer is alloc by the user
 *                      size - Total size of transmission
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : 0 - Sucessfully
 *                     !0 - Failed
 *
 * Description        : Reading data from Flash, default use direct mode to read, if the address
 *                      beyond the return automatically switch to indirect mode reading
 * \endverbatim
 * Traceability       : None
 *******************************************************************************************************/
int32_t Xspi_IpMemoryRead(Xspi_IpHostType *host, uint32_t address, uint8_t* buf, uint32_t size)
{
    XSPI_INVALIDATE_CACHE(host->config.directBase + address, size);
    (void) Xspi_Memcopy((void *)buf, (void *)(host->config.directBase + address), size);
    return 0;
}

int32_t Xspi_IpMemoryWrite(Xspi_IpHostType *host, uint32_t address, const uint8_t* buf, uint32_t size)
{
    int32_t ret = XSPI_RET_OK;

    if (((host->memoryWriteCmd.proto.detail.dataRate == 1u) && !XSPI_IS_ALIGNED(size, 2u)) ||
        !XSPI_IS_ALIGNED(address, 4u) || !XSPI_IS_ALIGNED(buf, 4u))
    {
        ret = XSPI_RET_PARAMETER_ERR;
    }
    else
    {
        Xspi_IpCacheFlush(host, address, size);
        if (size <= host->config.fifoSize)
        {
            ret = Xspi_IpCommandWrite(host, &host->memoryWriteCmd, address, buf, size);
        }
        else
        {
            if (host->config.semagLockEnable == true)
            {
                if(SEMAG_E_OK != sdrv_semag_trylock(host->config.semagId))
                {
                    ret = XSPI_RET_FAILED;
                }
            }

            if (XSPI_RET_OK == ret)
            {
                Xspi_IpCmdSetup(host, XSPI_IP_INDIRECR_WRITE, &host->memoryWriteCmd);
                Xspi_IpIndirectTrigger(host, address, size, XSPI_IP_INDIRECR_WRITE);
                ret = Xspi_IpFifoWrite(host, buf, size);
                (void) Xspi_IpTxComplete(host);

                if (host->config.semagLockEnable == true)
                {
                    (void) sdrv_semag_unlock(host->config.semagId);
                }
            }
        }
    }
    return ret;
}


int32_t Xspi_IpCommandRead(Xspi_IpHostType *host, Xspi_IpCommandType *cmd, uint32_t address, uint8_t* buf, uint32_t size)
{
    int32_t ret = XSPI_RET_OK;
    if ((0u == cmd->dummy) && (XSPI_IP_SINGLE_LANS != cmd->proto.detail.dataLans))
    {
        /* Workaround: Read Dummy and MISC.IMMIDEATE can't be zero at the same time  */
        cmd->dummy = (uint8)(size * 2u);
    }

    if (host->config.semagLockEnable == true)
    {
        if(SEMAG_E_OK != sdrv_semag_trylock(host->config.semagId))
        {
            ret = XSPI_RET_FAILED;
        }
    }

    if (XSPI_RET_OK == ret)
    {
        Xspi_IpCmdSetup(host, XSPI_IP_INDIRECR_READ, cmd);
        Xspi_IpIndirectTrigger(host, address, XSPI_ROUNDUP(size, 2u), XSPI_IP_INDIRECR_READ);
        ret = Xspi_IpFifoRead(host, buf, size);
        (void) Xspi_IpRxComplete(host);

        if (host->config.semagLockEnable == true)
        {
            (void) sdrv_semag_unlock(host->config.semagId);
        }
    }

    return ret;
}

int32_t Xspi_IpCommandWrite(Xspi_IpHostType *host, Xspi_IpCommandType *cmd, uint32_t address, const uint8_t* buf, uint32_t size)
{
    int32_t ret = XSPI_RET_OK;
    if (host->config.semagLockEnable == true)
    {
        if(SEMAG_E_OK != sdrv_semag_trylock(host->config.semagId))
        {
            ret = XSPI_RET_FAILED;
        }
    }

    if (XSPI_RET_OK == ret)
    {
        Xspi_IpCmdSetup(host, XSPI_IP_INDIRECR_WRITE, cmd);
        ret = Xspi_IpFifoPreWrite(host, buf, size);
        Xspi_IpIndirectTrigger(host, address, size, XSPI_IP_INDIRECR_WRITE);
        (void) Xspi_IpTxComplete(host);

        if (host->config.semagLockEnable == true)
        {
            (void) sdrv_semag_unlock(host->config.semagId);
        }
    }

    return ret;
}

void Xspi_IpPotoSetup(Xspi_IpHostType *host)
{
    Xspi_IpCmdSetup(host, XSPI_IP_INDIRECR_WRITE, &host->memoryWriteCmd);
    Xspi_IpCmdSetup(host, XSPI_IP_DIRECR_READ, &host->memoryReadCmd);
}

int32_t Xspi_IpRefclkSetup(Xspi_IpHostType *host, uint32_t refClkHz)
{
    int32_t ret = XSPI_RET_OK;
    if ((NULL != host->config.setClkRate) && (NULL != host->config.getClkRate))
    {
        if (0 == host->config.setClkRate(host->config.id, refClkHz))
        {

            host->currentRefClkHz = host->config.getClkRate(host->config.id);
            XSPI_LOG_DEBUG("spinor host clock rate is %d!\n", host->currentRefClkHz);

            if (host->currentRefClkHz <= XSPI_DLL_BYPASS_MIN_REFCLK)
            {
                Xspi_IpDllEnable(host, true, 0, 0u, false);
                Xspi_IpDllEnable(host, true, 1, 0u, false);
            }
        }
        else
        {
            ret = XSPI_RET_FAILED;
        }
    }
    else if (0u == host->currentRefClkHz)
    {
        host->currentRefClkHz = refClkHz;
    }
    else
    {
        /* Do nothing */
    }

    /* setup base on refclk*/
    /* Set AXI access timeout threshold */
   Xspi_IpWriteBits(host, XSPI_IP_AXI_CTRL, XSPI_IP_TIMEOUT_THRE_LSB, 24U,
                   XSPI_IP_MS_2_TICKS(host->currentRefClkHz, 5U));

   Xspi_IpDelaySetup(host);

    return ret;
}

/** *****************************************************************************************************
 * \brief This function Configuring Flash size in the controller.
 *
 * \verbatim
 * Syntax             : void Xspi_IpSetSize(
 *                          Xspi_BusHandleType *nor)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : nor - Pointer to bus handler
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Configuring Flash size in the controller
 * \endverbatim
 * Traceability       : None
 *******************************************************************************************************/
void Xspi_IpSizeSetup(Xspi_IpHostType *host, uint8_t cs, uint32_t size)
{
    uint8_t sizeLog2;
    uint32_t reg = Xspi_IpReadl(host, XSPI_IP_DEV_SIZE) >> (cs * XSPI_IP_DEV_SIZE_SIZE_LSB);

    sizeLog2 = Xspi_IpLog2Uint(size) & XSPI_IP_DEV_SIZE_SIZE_MASK;

    if ((0U != sizeLog2) && (sizeLog2 != (reg & XSPI_IP_DEV_SIZE_SIZE_MASK)))
    {
        Xspi_IpWriteBits(host, XSPI_IP_DEV_SIZE, cs * XSPI_IP_DEV_SIZE_SIZE_LSB, 5U, sizeLog2);
        XSPI_LOG_DEBUG("xspi dev size reg = 0x%x\n", Xspi_IpReadl(host, XSPI_IP_DEV_SIZE));
    }
    host->devSize[cs] = size;
    host->totalSize = host->devSize[0] + host->devSize[1];
}

void Xspi_IpGetDevSize(Xspi_IpHostType *host, uint8_t csNum)
{
    uint8_t i;
    uint32_t sizeLog2;

    host->totalSize = 0u;
    for (i = 0u; i < csNum; i++)
    {
        sizeLog2 = (Xspi_IpReadl(host, XSPI_IP_DEV_SIZE) >> (i * XSPI_IP_DEV_SIZE_SIZE_LSB))
                & XSPI_IP_DEV_SIZE_SIZE_MASK;
        host->devSize[i] = 1UL << sizeLog2;
        host->totalSize += host->devSize[i];
    }
}

void Xspi_IpDqsEnable(Xspi_IpHostType *host, bool enable)
{
    /* For aviod dqs bug */
    Xspi_IpWriteBits(host, XSPI_IP_MISC, XSPI_IP_MISC_RX_ENABLE_MODE_LSB, 1U, (true == enable) ? 1U : 0U);

    /* Set rx mode */
    Xspi_IpRxModeConfig(host, (true == enable) ? 2u : 0u);

    if (host->currentRefClkHz <= XSPI_DLL_BYPASS_MIN_REFCLK)
    {
        if (true == enable)
        {
            Xspi_IpDllEnable(host, true, 0, 22u, true);
            Xspi_IpDllEnable(host, true, 1, 22u, true);
        }
        else
        {
            Xspi_IpDllEnable(host, true, 0, 0u, false);
            Xspi_IpDllEnable(host, true, 1, 0u, false);
        }
    }

    host->dqsEnable = enable;
}

void Xspi_IpCommandSetup(Xspi_IpHostType *host, uint32_t memoryReadProto,
    uint8_t readDummy, uint32_t memoryWriteProto, uint8_t writeDummy, uint8_t addrWidth)
{
    host->memoryReadCmd.dummy = readDummy;
    host->memoryReadCmd.proto.u32 = memoryReadProto;
    host->memoryReadCmd.addrBytes = addrWidth;
    host->memoryWriteCmd.dummy = writeDummy;
    host->memoryWriteCmd.proto.u32 = memoryWriteProto;
    host->memoryWriteCmd.addrBytes = addrWidth;
}

int32_t Xspi_IpRfdSetup(Xspi_IpHostType *host)
{
    int32_t ret = XSPI_RET_OK;
    uint32_t tmt;
    uint8_t i;
    uint32_t reg;
    uint8_t regionMask;

    if (host->rfdEnable == true)
    {
        regionMask = Xspi_IpRfdCheck(host);
        if (0u == regionMask)
        {
            /* Do nothing */
        }
        else
        {
            Xspi_IpCmdSetup(host, XSPI_IP_INDIRECR_READ, &host->memoryReadCmd);
            for (i = 0; i < XSPI_IP_MAX_RFD_REGION; i++)
            {
                if (0U != (regionMask & (1u << i)))
                {
                    /* Key derivation trigger */
                    reg = Xspi_IpReadl(host, XSPI_IP_IMG_RFD);
                    reg |= XSPI_BIT(8U + i);
                    Xspi_IpWritel(host, XSPI_IP_IMG_RFD, reg);

                    /* Polling key ready */
                    tmt = XSPI_IP_KEY_READY_TIMEOUT_CYCLES;

                    while (0U == (Xspi_IpReadl(host, XSPI_IP_IMG_RFD) & XSPI_BIT(16U + i)))
                    {
                        if (0U == tmt)
                        {
                            break;
                        }
                        tmt--;
                        XSPI_UDELAY(1);
                    }
                }
            }

            /* Enable decryption */
            reg = Xspi_IpReadl(host, XSPI_IP_IMG_RFD);
            reg |= ((uint32_t)regionMask << 28);
            Xspi_IpWritel(host, XSPI_IP_IMG_RFD, reg);

            /* Flush prefetch */
            if (host->prefetchEnable == true)
            {
                Xspi_IpPrefetchFlush(host);
            }
        }
    }
    return ret;
}

void Xspi_IpByteSwapSetup(Xspi_IpHostType *host, bool enable)
{
    Xspi_IpWriteBits(host, XSPI_IP_MODE_CTRL, XSPI_IP_MODE_CTRL_BYTE_SWAP_LSB, 1U, (true == enable) ? 1u : 0u);
}

int32_t Xspi_IpSetFirewall(Xspi_IpHostType *host, uint32_t addr,
                        uint32_t size, Xspi_IpFwConfigType const *config, uint32 num)
{
    int32_t ret = XSPI_RET_OK;
    uint32_t i;
    uint8_t regionId = 0u;

    /* Check parameters */
    if (!XSPI_IS_ALIGNED(addr, 0x1000u) || !XSPI_IS_ALIGNED(size, 0x1000u))
    {
        XSPI_LOG_DEBUG("The address:%x or length:%x not 4k aligned\n", addr, size);
        ret = XSPI_RET_PARAMETER_ERR;
    }
    else
    {

        if (0 != Xspi_IpAddFirewallRegion(host, addr, size, &regionId))
        {
            ret = XSPI_RET_FAILED;
            XSPI_LOG_DEBUG("Can not add a firewall region, (%x %x)\n", addr, size);
        }
        else
        {
            for (i = 0; (i < num) && (XSPI_RET_OK == ret); i++)
            {
                ret = Xspi_IpFirewallAccessConfig(host, regionId, &config[i]);
            }
        }
    }

    return ret;
}

void Xspi_IpCacheFlush(Xspi_IpHostType *host, uint32_t addr, uint32_t length)
{

    uint32_t addrSkipStart = XSPI_ROUNDDOWN(addr, XSPI_MAX_RBUF_BLOCK_SIZE);
    uint32_t addrSkipEnd = XSPI_ROUNDUP(addr + length, XSPI_MAX_RBUF_BLOCK_SIZE);
    uint32_t i, cnt;

    XSPI_INVALIDATE_CACHE((uint32_t)(host->config.directBase + addr), length);
    if (host->prefetchEnable == FALSE)
    {
        /* Do nothing */
    }
    else if ((false == host->config.useRomConfig) && (false == host->useDummyRead))
    {
        Xspi_IpPrefetchFlush(host);
    }
    else
    {
        cnt = 0;
        for (i = 0; (i < host->totalSize) && (cnt < XSPI_MAX_RBUF_ENTRY_NUM); i += XSPI_MAX_RBUF_BLOCK_SIZE) {
           if ((i >= addrSkipStart )&& (i <= addrSkipEnd)) {
                /* PRQA S 2469 1 */
                i = addrSkipEnd;
           }
           else
           {
                XSPI_INVALIDATE_CACHE((uint32_t)(host->config.directBase + i), 128u);
                (void) readl((uint32_t)host->config.directBase + i);
                cnt++;
           }
       }
    }
}

#ifdef CFG_PLATFORM_MCAL
#define FLS_STOP_SEC_CODE
#include "Fls_MemMap.h"
#endif /* #ifdef CFG_PLATFORM_MCAL */
/* End of file */


